<template>
  <div :class="rootClass">
    <el-form-item :prop="item.name || ''" :label="item.label" v-bind="item.formItemProps || {}" ref="el-form-item">
      <el-upload
        ref="uploadElem"
        :classes="opt.disabled ? 'disabled_upload' : '' "
        v-bind="opt"
        :file-list="fileList"
        :on-change="onChange"
        :on-preview="onPreview"
        :on-remove="onRemove"
        :before-remove="beforeRemove"
        :on-progress="onProgress"
        :on-success="onSuccess"
        :on-error="onError"
        :on-exceed="onExceed"
        :before-upload="beforeUpload"
        :class="uploadComponentClassValue"
      >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text" v-if="opt.drag ">
          将文件拖到此处，或
          <em>点击上传</em>
        </div>
        <div class="el-upload__tip" slot="tip" v-if="opt.tips">{{opt.tips}}</div>
      </el-upload>

      <div class="null-label" v-if="!!opt.nullLabel && fileList.length == 0">{{opt.nullLabel}}</div>

      <div class="buttons" v-if="!opt.disabled">
        <el-button
          size="mini"
          type="success"
          :disabled="fileList.length == 0 || uploading"
          @click="upload"
          v-if="!opt.autoUpload && !hiddenUploadButton"
        >上传到服务器</el-button>
      </div>
    </el-form-item>

    <div ref="hiddenElem" style="visibility: hidden;position: absolute;z-index: -999;"></div>

    <el-dialog
      title="预览"
      top="5vh"
      append-to-body
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      :visible.sync="displayPreview"
      :width="opt.previewWidth"
      @closed="onPreviewClose"
    >
      <div v-if="previewType == 'image'">
        <el-image :src="previewUrl" style="width: 100%;" :preview-src-list="[ previewUrl ]"></el-image>
      </div>
      <div v-if="previewType == 'video'">
        <video
          ref="videoPlayer"
          :src="previewUrl"
          class="video_player_item"
          controls="controls"
          controlslist="nodownload"
        >您的浏览器不支持视频播放</video>
      </div>
      <div v-if="previewType == 'audio'">
        <audio
          ref="audioPlayer"
          :src="previewUrl"
          class="audio_player_item"
          controls="controls"
          controlslist="nodownload"
        ></audio>
      </div>
    </el-dialog>
  </div>
</template>

<script>
  import { objectAssign, formatDate } from "../../utils/common";
  import uploadConfig from "../../config/upload";
  import serverUpload from "../../utils/upload/server";
  import Required from "../validMixins/Required";

  /**
   * 服务器文件上传， 服务器上传地址的配置，在 config/upload中。
   * 请求返回结果集格式为：
      {
          code: 200,
          msg: "success",
          data: "http://aiyis-res.oss-cn-beijing.aliyuncs.com/backe…/07/20/f56ff0e80206f3e2a9d1cfa1ee2b9df7_knOvj.mp4"
      }
   */
  export default {
    name: "PopoServerUpload",
    props: {
      value: { type: [String, Array] },
      item: { type: Object },
      formData: { type: Object },
    },
    mixins: [Required],
    data() {
      return {
        mvalue: this.value,
        opt: {},
        fileList: [],

        rootClass: {},
        uploadComponentClass: {},

        // 保存文件上传时的排序，因为不同文件上传后，排序可能会变
        fileUploadOrder: [],

        // 显示预览窗口
        displayPreview: false,
        // 预览的文件类型，仅支持image/video/audio
        previewType: "",
        // 预览的URL地址
        previewUrl: "",

        // 是否正在上传
        uploading: false,

        // 是否强制隐藏上传按钮
        hiddenUploadButton: false,
      };
    },
    watch: {
      mvalue(val) {
        this.$emit("input", val);
      },
    },
    computed: {
      uploadComponentClassValue: function () {
        return { hide: this.hideUploadEdit, ...this.uploadComponentClass };
      },
      // 是否隐藏上传的按钮（文件数满的时候隐藏）
      hideUploadEdit: function () {
        return !!this.opt.disabled || this.fileList.length >= this.opt.limit || this.hiddenUploadButton;
      },
    },
    created() {
      // console.log( "input upload", this );
      var opt = objectAssign(
        {
          limit: this.item.limit || 1,
          multiple: this.item.multiple !== undefined ? this.item.multiple : false,
          tips: this.item.tips !== undefined ? this.item.tips : null,
          previewWidth: this.item.previewWidth !== undefined ? this.item.previewWidth : "550px",
          autoUpload: this.item.autoUpload !== undefined ? this.item.autoUpload : false,
          nullLabel: this.item.nullLabel !== undefined ? this.item.nullLabel : null,
          // drag : this.item.drag !== undefined ? this.item.drag : true,
        },
        this.item.props
      );

      // 将已有的数据添加进组件中
      if (!(this.mvalue instanceof Array) && !!this.mvalue && opt.limit > 1) {
        this.mvalue = this.mvalue.split(",");
      }
      this.fileList = this.getUploadFileListInfo(this.mvalue);

      var fileType = this.item.fileType || "";

      var accept_fast = {
        image: "image/*",
        video: "video/*",
        audio: "audio/*",
      };
      opt.accept = accept_fast[fileType] !== undefined ? accept_fast[fileType] : fileType;
      opt.action = uploadConfig.server.action;
      // opt.action = "";
      opt.httpRequest = this.httpRequest;
      opt.drag = true;

      if (fileType == "image") {
        opt.listType = "picture-card";
        opt.drag = false;
        // opt.showFileList = false;
      }

      // opt.autoUpload = false;
      this.opt = opt;
    },
    methods: {
      // 获得指定地址的后缀和文件名，初始化el-upload的文件列表时用的
      getUploadFileListInfo(list) {
        if (!list) return [];

        list = Array.isArray(list) ? list : [list];
        var _list = (list || []).map((path) => {
          var url = path || "";
          var fileName = path.substr(path.lastIndexOf("/") + 1);
          return {
            name: fileName,
            url: url,
          };
        });
        return _list;
      },
      // 获得统一的文件命名方式
      getRandomFileInfo(file) {
        let name = file.name;
        let ext = name.substr(name.lastIndexOf("."));
        let _name = name.substr(0, name.lastIndexOf("."));
        let fileName = [
          formatDate(new Date(), "yyyy/MM/dd/hhmmss"),
          Math.random().toString(36).substr(3, 8),
          _name.replace(/[\u4e00-\u9fa5]/gim, ""),
        ].join("_");
        // let fileName =  + "_" + ;
        fileName += ext;
        let filePath = this.item.uploadFilePath || "/upload/resource/";
        let fileFinalPath = filePath + fileName;
        return {
          path: filePath,
          name: fileName,
          final: fileFinalPath,
        };
      },
      onExceed() {
        this.$alert("文件超出最大上传个数", "提示");
      },
      onChange(file, fileList) {
        this.fileList = this.fileList.filter((item) => {
          return item.uid != file.uid && item.status != "fail";
        });

        // var _file_names = fileList.map( ( item) => { return item.uid;})

        // 检验文件格式
        // console.log( "onChange", _file_names.join(","), fileList);
        if (file.status == "fail") return;

        var accept = this.opt.accept;
        console.log("file fileType：", file.raw.type);

        let me = this;
        // 校验文件的长宽高和文件大小
        var promise = new Promise((resolve, reject) => {
          var _file = file.raw,
            isImage = _file.type.indexOf("image") != -1,
            isVideo = _file.type.indexOf("video") != -1;

          // 过滤非法的文件格式，仅对input[type=file]的File文件有效，
          // 对网络文件因获取不到文件的accept，所以无效。
          if (!!accept) {
            accept = accept.replace(/\*/gim, "");
            accept = accept.split(",");
            // console.log( "accept", accept);

            var rawType = file.raw ? file.raw.type : file.name;
            var some = accept.some((_accept) => {
              return rawType.indexOf(_accept) >= 0 || file.name.substr(file.name.lastIndexOf(".")).indexOf(_accept) >= 0;
            });

            if (!some) {
              this.$message.error("选择的文件格式不正确");
              reject();
              return;
              // fileList = fileList.filter( ( item) => {
              //     return item.uid != file.uid;
              // });
            }
          }

          if (this.item.maxFileSize) {
            // console.log( "this.item", this.item);
            // 判断文件大小
            let fileSize = _file.size / 1024 / 1024;
            // console.log( "this.item", fileSize, (fileSize > this.item.maxFileSize));
            if (fileSize > this.item.maxFileSize) {
              this.$message.error("上传的文件不得超过" + this.item.maxFileSize + "Mb");
              reject();
              return;
            }
          }

          if (this.item.mediaWidth || this.item.mediaHeight) {
            // 判断文件大小
            var out_msg = [];
            out_msg.push(this.item.mediaWidth ? "宽" + this.item.mediaWidth + "像素" : null);
            out_msg.push(this.item.mediaHeight ? "高" + this.item.mediaHeight + "像素" : null);
            out_msg = out_msg
              .filter((item) => {
                return item != null;
              })
              .join("、");
            // console.log( "out_msg", out_msg);

            if (isImage) {
              this.getBlobPreviewUrl(_file).then((url) => {
                var img = new Image();
                img.onload = () => {
                  if (
                    (this.item.mediaWidth && img.width != this.item.mediaWidth) ||
                    (this.item.mediaHeight && img.height != this.item.mediaHeight)
                  ) {
                    this.$message.error("请上传" + out_msg + "的图片");
                    reject();
                    return;
                  }
                  resolve();
                };
                img.src = url;
              });

              return;
            }

            if (isVideo) {
              this.getBlobPreviewUrl(_file).then((url) => {
                // console.log( "isVideo");
                var videoElement = document.createElement("video");
                videoElement.onloadeddata = (event) => {
                  var target = event.target;
                  var width = target.offsetWidth;
                  var height = target.offsetHeight;

                  if (
                    (this.item.mediaWidth && width != this.item.mediaWidth) ||
                    (this.item.mediaHeight && height != this.item.mediaHeight)
                  ) {
                    this.$message.error("请上传" + out_msg + "的视频");
                    reject();
                    return;
                  }
                  resolve();
                  return;
                };
                let hiddenElem = this.$refs["hiddenElem"];
                hiddenElem.appendChild(videoElement);
                videoElement.src = url;
                // console.log( "hiddenElem", hiddenElem);
              });
              return;
            }
          }

          resolve();
        });

        promise
          .then((fileList) => {
            // console.log( "promise then");
            // this.fileList = fileList;
            this.fileList.push(file);
          })
          .catch(() => {});
        return false;
      },
      // 从网络地址获得File对象
      getNetFileObject(url, imageName) {
        // imageName一定要带上后缀
        let p = new Promise((resolve, reject) => {
          var blob = null;
          var xhr = new XMLHttpRequest();
          xhr.open("GET", url);
          // xhr.setRequestHeader('Accept', 'image/jpeg');
          xhr.responseType = "blob";

          var file_ext = url.substr(url.lastIndexOf(".") + 1);
          // console.log( "file_ext", file_ext);
          xhr.onload = () => {
            blob = xhr.response;
            // let imgFile = new File([blob], imageName, {type: 'image/jpeg'});
            let file = new File([blob], imageName);
            resolve(file);
          };
          xhr.send();
        });
        return p;
      },
      getBlobPreviewUrl(file) {
        var promise = new Promise((resolve, reject) => {
          var reader = new FileReader();
          reader.onload = (e) => {
            var bf = e.target.result;
            var blob = new Blob([bf]);
            var str = URL.createObjectURL(blob);
            resolve(str);
          };
          reader.readAsArrayBuffer(file);
        });

        return promise;
      },
      onPreview(file) {
        var previewType = "";
        // console.log( "onPreview", file);

        // if( !file.raw && file.url){
        //     this.getNetFileObject( file.url, file.name).then( (file) =>{
        //         // console.log( "getNetFileObject", file);
        //     });
        // }

        if (file.raw && file.raw instanceof File) {
          var ftype = file.raw.type;
          ["image", "video", "audio"].forEach((type) => {
            if (ftype.indexOf(type + "/") == 0) {
              previewType = type;
            }
          });
        } else if (!!file.url) {
          var url = file.url;
          var file_ext = url.substr(url.lastIndexOf(".") + 1);
          var file_map = {
            xbm: "image",
            tif: "image",
            pjp: "image",
            png: "image",
            jpg: "image",
            jpeg: "image",
            pjpeg: "image",
            gif: "image",
            bmp: "image",
            webp: "image",
            ico: "image",
            tiff: "image",
            tif: "image",
            svgz: "image",

            mp3: "audio",
            weba: "audio",
            webm: "audio",
            opus: "audio",
            flac: "audio",
            m4a: "audio",
            ogg: "audio",
            mid: "audio",
            aiff: "audio",
            wma: "audio",
            au: "audio",

            mp4: "video",
            ogm: "video",
            wmv: "video",
            mpeg: "video",
            asx: "video",
            mpg: "video",
            ogv: "video",
            webm: "video",
            mov: "video",
            m4v: "video",
            avi: "video",
          };

          previewType = file_map[file_ext] || this.fileType || "";
        }

        if (!previewType) {
          if (file.url) {
            this.$confirm("该文件暂时无法预览，请问你是否需要在浏览器中打开？", {
              confirmButtonText: "在浏览器新窗口中打开",
            }).then(() => {
              window.open(file.url, "_blank");
            });
          } else {
            this.$message.alert("该文件暂时不支持预览");
          }

          return;
        }

        if (file.url) {
          this.previewUrl = file.url;
          this.previewType = previewType;
          this.displayPreview = true;
        } else {
          this.getBlobPreviewUrl(file.raw).then((url) => {
            file.url = url;
            this.onPreview(file);
          });
        }
      },
      onPreviewClose() {
        if (this.previewType == "image") {
        }
        if (this.previewType == "video") {
          this.$refs.videoPlayer && this.$refs.videoPlayer.pause();
        }
        if (this.previewType == "audio") {
          this.$refs.audioPlayer && this.$refs.audioPlayer.pause();
        }
      },
      beforeRemove() {
        // 上传过程中不要删除
        return !this.uploading;
      },
      onRemove(file, fileList) {
        this.fileList = fileList;
        this.setMvalue(fileList);
      },
      onProgress(percentage, file, fileList) {
        // file.percentage = percentage;
        // console.log( "onProgress", file.percentage, file, fileList);
      },
      onSuccess(response, file, fileList) {
        // console.log( "onSuccess", response, file, fileList );

        var everyFinish = fileList.every((file) => {
          return file.status == "success";
        });

        if (everyFinish) {
          var orders = this.fileUploadOrder;

          var _list = [];
          orders.forEach((key) => {
            var file = this.fileList.find((file) => {
              return key == file.name + "_" + file.uid;
            });
            if (file) {
              _list.push(file);
            }
          });

          setTimeout(() => {
            this.setMvalue(_list);
            this.uploading = false;
            this.fileList = _list.slice(0);
            this.$emit("asynNotify", "finish");
          }, 500);
        }
      },
      setMvalue(fileList) {
        var _list = [];
        fileList.forEach((file) => {
          if (file.status == "success") {
            _list.push(file.response ? file.response.data : file.url);
          }
        });
        this.mvalue = _list;
      },
      onError(err, file, fileList) {
        this.uploading = false;
        this.$emit("asynNotify", "finish");
        console.error("onError", err, file, fileList);
      },
      beforeUpload(file) {
        this.fileUploadOrder.push(file.name + "_" + file.uid);
        // console.log( "before upload =================================" );
        this.$emit("asynNotify", "doing");
        this.uploading = true;
      },
      upload() {
        this.$refs.uploadElem.submit();
      },
      httpRequest(http) {
        serverUpload(http.file, {
          progress: (e) => {
            http.onProgress({ percent: e.percent });
          },
          success: (e) => {
            http.onSuccess(e);
          },
          failure: (e) => {
            console.error("上传失败", e);
            http.onError("上传失败");
          },
        });
      },
    },
  };
</script>

<style scoped lang="scss">
::v-deep {
  .hide {
    .el-upload--picture-card,
    .el-upload {
      display: none;
    }
  }
  .disabled_upload .el-upload--picture-card {
    display: none;
  }
  .el-message-box {
    min-width: 300px;
  }
  .el-image-viewer__close {
    background-color: #fff;
  }
  .el-upload-list__item {
    cursor: pointer;
  }
  .el-upload-list--picture .el-upload-list__item-thumbnail {
    object-fit: contain;
  }
  .el-upload-dragger {
    height: 110px;
  }
  .el-upload-dragger .el-icon-upload {
    margin-top: 10px;
    margin-bottom: 10px;
  }
  .el-upload__tip {
    margin-top: 2px;
    line-height: 18px;
  }
}
.buttons {
  text-align: center;
  margin-top: 5px;
}

.video_player_item {
  display: block;
  width: 100%;
  height: 300px;
}
.audio_player_item {
  display: block;
  width: 100%;
}
.null-label {
  color: #b7bdca;
  font-size: 12px;
}
</style>
